import { fabric } from 'fabric'
import { Canvas } from 'fabric/fabric-impl'
import { BasicItem } from './BasicItem'
import { ChildItemOption, BoundingBox, hasParentType } from './types/global'
import DaoDaoMindMap from './DaodaoMindMap'
import { ExpandButton } from './ExpandButton'

export class ChildItem extends BasicItem{
	canvas: Canvas
	topLevel: DaoDaoMindMap
	option: ChildItemOption
	parent: ChildItem | null
	img: hasParentType<fabric.Image> | null
	children: ChildItem[]
	totalchildHeight: number
	totalchildNum: number
	boundingBoxWidthChild: BoundingBox
	bounding: fabric.Rect
	level: number
	afterLine: fabric.Line | null
	frontLine: fabric.Path | null
	expandButton: ExpandButton
	visible: boolean
	childrenVisible: boolean
	tempChildrenVisible: boolean
	isActive: boolean
	icons: (fabric.Object|fabric.Group)[]
	[propName:string]: unknown //允许用户往上面挂载数据
	constructor(topLevel: DaoDaoMindMap, option: ChildItemOption = {}) {
		super(topLevel.canvas as Canvas, option)
		this.canvas = topLevel.canvas as Canvas
		this.topLevel = topLevel
		this.option = option
		this.parent = option.parent || null
		this.img = null
		this.children = []
		this.totalchildHeight = 0
		this.totalchildNum = 0
		this.boundingBoxWidthChild = {
			top:0,
			bottom:0,
			left:0,
			right:0
		}
		this.bounding = new fabric.Rect({
			top: 0,
			left: 0,
			width: 0,
			height: 0,
			stroke: 'transparent',
			fill:'transparent',
			selectable:false,
		})
		this.level = 0
		this.afterLine = null
		this.frontLine = null
		this.expandButton = new ExpandButton(this.canvas, this)
		this.icons = []
		this.visible = true
		this.childrenVisible = true
		this.tempChildrenVisible = true
		this.isActive = false
		this.initItem()
	}
	initItem() {
		this.iText.parent = this
		this.rect.parent = this
		this.resizeBtn.parent = this
		this.canvas.add(this.bounding)
		this.bounding.sendToBack()
		this.parent && this.parent?.children.push(this)
		this.expandButton.update()
		if(this.option.icons && this.option.icons.length > 0) {
			this.option.icons.forEach(item => {
				this.addIcon(item.path, item.clickFn, item.hoverFn)
			})
		}
		this.iText.setOptions({
			'lockMovementX': true,
			'lockMovementY': true
		})
		if(this.option.width) {
			this.hasChangeWidth = true
			this.iText.splitByGrapheme = true
			this.iText.set({width: this.option.width})
		}
		this.staticStyle = this.option.style || {}
		if(this.option.img && this.option.img.src) {
			this.addImageBySrc(this.option.img.src)
			if(this.option.img.width) {
				this.img?.set({width: this.option.img.width})
			}
			if(this.option.img.height) {
				this.img?.set({height: this.option.img.height})
			}
		}
		this.resizeBtn.on('mousemove',() => {
			if(this.resizeflag) {
				this.topLevel.sortFlag = false
				this.topLevel.countMapPosition()
			}
		})
		this.iText.on('changed',() => {
			setTimeout(() => {
				this.topLevel.countMapPosition()
			},20)
		})
		this.iText.on('resizing',() => {
			this.topLevel.sortFlag = false
			this.topLevel.countMapPosition()
		})
	}
	addIcon(path: string, clickFn?: (event:{target: ChildItem}) => void, hoverFn?: (event:{target: ChildItem}) => void) {
		fabric.loadSVGFromURL(path, (objects, options) => { 
			console.log(objects, options)
			const obj = fabric.util.groupSVGElements(objects, options)
			obj.on('mouseover', () => {
				obj.set({fill: '#ffa261'})
				this.canvas.requestRenderAll()
				if(hoverFn) {
					hoverFn({target: this})
				}
			})
			obj.on('mouseout', () => {
				obj.set({fill: '#000'})
				this.canvas.requestRenderAll()
			})
			if(clickFn) {
				obj.on('mouseup', () => {
					clickFn({target: this})
				})
			}
			const scaleY = obj.height ? 16 / obj.height : obj.scaleY
			this.icons.push(obj)
			obj.set({ 
				borderColor: 'transparent', // 控制器边框颜色
				scaleX: scaleY,
				scaleY: scaleY
			})

			obj.hasControls = false

			this.canvas.add(obj)

			this.redrawBox()
			this.topLevel._refresh() 
		})
	}
	addImageBySrc(src: string) {
		if(src) {
			if(this.img){
				this.img.setSrc(src,() => {
					this.redrawBox()
					this.topLevel.countMapPosition()
					this.topLevel._refresh()
				})
			}else{
				fabric.Image.fromURL(
					src, // 真实图片地址
					img => {
						this.img = img
						this.img.set({
							lockMovementX:true,
							lockMovementY: true
						})
						this.img.parent = this
						this.img.setControlsVisibility({
							'mtr':false
						})
						this.img.on('scaling',() => {
							console.log('scaling')
							this.topLevel.sortFlag = false
							this.redrawBox()
							this.topLevel.countMapPosition()
						})
						this.canvas.add(this.img)
						this.redrawBox()
						this.topLevel.countMapPosition()
						this.topLevel._refresh()
					}
				)
			}
		}
	}
	addImage(file: File | null) {
		console.log(file)
		if(file){
			const reader = new FileReader()
			reader.readAsDataURL(file)

			// 图片文件完全拿到后执行
			reader.onload = () => {
				// 转换成base64格式
				const imgPath = reader.result as string
				if(imgPath) {
					this.addImageBySrc(imgPath)
				}
			}
		}
	}
	deleteImage() {
		if(this.img){
			this.canvas.remove(this.img)
			this.img = null
			this.redrawBox()
			this.topLevel.countMapPosition()
		}
	}
	getHeight() {
		return this.rect.getScaledHeight()
	}
	getWidth() {
		return this.rect.getScaledWidth()
	}
	redrawBox() {
		if(this.iText && this.rect) {
			const zoom = this.canvas.getZoom()
			this.iText.padding = this.padding*zoom
			let imgWidth = 0
			let imgHeight = 0
			const iTextWidth = ((this.iText as fabric.Textbox)?.width || 0)
			if(this.img) {
				this.img.set({
					minScaleLimit: 0,
					left: (this.iText.left || 0),
					top: (this.iText.top || 0) + ((this.iText as fabric.Textbox)?.height || 0) + 4
				})
				imgWidth = this.img.getScaledWidth() || 0
				imgHeight = (this.img.getScaledHeight() || 0 + 4)
			}
			const rectLeft = (this.iText.left || 0) - this.padding
			const rectTop = (this.iText.top || 0) - this.padding
			const rectWidth = iTextWidth > imgWidth ? iTextWidth + this.padding * 2 : imgWidth + this.padding * 2
			const rectHeight = ((this.iText as fabric.Textbox)?.height || 0) + this.padding * 2 + imgHeight
			this.rect.set({
				left: rectLeft,
				top: rectTop,
				width: rectWidth,
				height: rectHeight
			})
			this.resizeBtn.set({
				left: rectLeft + rectWidth,
				top: rectTop,
				height: rectHeight
			})
			this.iText.setCoords()
			this.rect.setCoords()
			this.img?.setCoords()
			this.expandButton && this.expandButton.update()
			if(this.icons && this.icons.length > 0) {
				if(this.rect.aCoords) {
					const origin = this.rect.aCoords.tr
					let left = origin.x + 5
					for(let i = 0;i<this.icons.length; i++) {
						left = left - this.icons[i].getScaledWidth() - 5
						const top = origin.y - this.icons[i].getScaledHeight() - 2
						this.icons[i].set({
							left: left,
							top: top
						})
					}
				}
			}
			this.canvas.requestRenderAll()
		}
	}
	changePosition(offset: {x: number, y:number}) {
		if(this.parent && this.parent.iText) {
			const x = (this.parent.iText.left || 0) + offset.x
			const y = (this.parent.iText.top || 0) + offset.y

			this.iText.setPositionByOrigin(new fabric.Point(x,y),'left','top')
			this.redrawBox()

			const x0 = (this.parent.rect.left||0) + this.parent.rect.getScaledWidth()
			const y0 = (this.parent.rect.top||0) + this.parent.rect.getScaledHeight() / 2
			const x2 = (this.rect.left || 0)
			const y2 = (this.rect.top || 0) + this.rect.getScaledHeight() / 2
			const x1 = x0
			const y1 = y2
			
			this.updateLine(x0,y0,x1,y1,x2,y2)

			this.canvas.requestRenderAll()
		}else{
			this.iText.setPositionByOrigin(new fabric.Point(offset.x,offset.y),'left','top')
			this.frontLine && this.canvas.remove(this.frontLine)
			this.redrawBox()
		}
	}
	updateLine(x0:number,y0:number,x1:number,y1:number,x2:number,y2:number) {
		if(!this.visible) {
			return
		}
		const afterLineWidth = this.topLevel.afterLineLength
		if(!this.frontLine) {
			this.frontLine = new fabric.Path(`M ${x0 + afterLineWidth} ${y0} Q ${x1 + afterLineWidth}, ${y1}, ${x2}, ${y2}`, { fill: '', stroke: 'black', objectCaching: false, selectable: false })
			this.canvas.add(this.frontLine)
		}else{
			this.canvas.remove(this.frontLine)
			this.frontLine = new fabric.Path(`M ${x0 + afterLineWidth} ${y0} Q ${x1 + afterLineWidth}, ${y1}, ${x2}, ${y2}`, { fill: '', stroke: 'black', objectCaching: false, selectable: false })
			this.canvas.add(this.frontLine)
		}
		this.frontLine.sendToBack()
		this.canvas.requestRenderAll()
	}
	updateAfterLine() {
		if(!this.childrenVisible && this.afterLine) {
			this.afterLine.visible = false
			return
		}
		if(!this.visible) {
			return
		}
		if(this.afterLine) {
			this.canvas.remove(this.afterLine)
			this.afterLine = null
		}
		if(this.children.length > 0 && this.childrenVisible) {
			const afterLineWidth = this.topLevel.afterLineLength
			const x0 = (this.rect.left||0) + this.rect.getScaledWidth()
			const y0 = (this.rect.top||0) + this.rect.getScaledHeight() / 2 - 0.5
			this.afterLine = new fabric.Line([x0, y0, x0 + afterLineWidth, y0],{ fill: 'black', stroke: 'black', objectCaching: false, selectable: false })
			this.canvas.add(this.afterLine)
			this.afterLine.sendToBack()
		}
	}
	// show和hide都是控制其子级显示的
	show() {
		this.childrenVisible = true
		if(this.afterLine) this.afterLine.visible = true
		this.children.forEach(child => {
			child.childrenVisible = true
			child.visible = true
			child.rect.visible = true
			child.iText.visible = true
			if(child.afterLine) child.afterLine.visible = true
			if(child.frontLine) child.frontLine.visible = true
			if(child.img) child.img.visible = true
			child.icons.forEach(icon => icon.visible = true)
			child.bounding.visible = true
			child.show()
		})
	}
	hide() {
		this.childrenVisible = false
		if(this.afterLine) this.afterLine.visible = false
		this.children.forEach(child => {
			child.childrenVisible = true
			child.visible = false
			child.rect.visible = false
			child.iText.visible = false
			if(child.afterLine) child.afterLine.visible = false
			if(child.frontLine) child.frontLine.visible = false
			if(child.expandButton) child.expandButton.hide()
			child.icons.forEach(icon => icon.visible = false)
			if(child.img) child.img.visible = false
			child.bounding.visible = false
			child.hide()
		})
	}
	remove() {
		console.log('remove')
		const removeList: ChildItem[] = []
		
		this.removeItem(removeList)

		console.log(removeList)
		
		removeList.forEach(current => {
			//mapdata数组中删除该项
			const index = this.topLevel.mapData.findIndex(item => item === current)
			current.topLevel.mapData.splice(index,1)
			//从父元素的children数组中删除该项
			if(current.parent) {
				const parentIndex = current.parent.children.findIndex(item => item === current)
				current.parent.children.splice(parentIndex,1)
			}
		})

		this.topLevel._refresh()
	}
	removeItem(removeList: ChildItem[]) {
		if(this.topLevel.mapData.includes(this)){
			this.children.forEach(child => {
				child.removeItem(removeList)
			})
			removeList.push(this)
			this.canvas.remove(this.iText)
			this.canvas.remove(this.rect)
			this.frontLine && this.canvas.remove(this.frontLine)
			this.afterLine && this.canvas.remove(this.afterLine)
			this.expandButton && this.expandButton.remove()
			this.img && this.canvas.remove(this.img)
			this.resizeBtn && this.canvas.remove(this.resizeBtn)
			this.bounding && this.canvas.remove(this.bounding)
		}
	}
}